﻿using Basic.ScheduledTask.Abstract;
using Hangfire;
using Microsoft.Extensions.Options;
using System.Linq.Expressions;

namespace Basic.ScheduledTask.HangfireImplement
{
    /// <summary>
    /// 基于Hangfire的定时任务管理
    /// </summary>
    public class HangfireJobManager : IJobManager
    {
        private RecurringJobOptions JobOptions;
        public HashSet<string> LoadedJobIds { get; }

        public HangfireJobManager(IOptions<JobDbConfig> options)
        {
            LoadedJobIds = new HashSet<string>();
            JobOptions = new RecurringJobOptions
            {
                TimeZone = TimeZoneInfo.Local,
                MisfireHandling = MisfireHandlingMode.Relaxed
            };
        }

        #region 同步

        public void AddOnceJob(Expression<Action> expression) => BackgroundJob.Enqueue(expression);

        public void AddOnceJob(Expression<Action> expression, DateTimeOffset time) => BackgroundJob.Schedule(expression, time);

        public void DelayJob(Expression<Action> expression, TimeSpan delayTime) => BackgroundJob.Schedule(expression, delayTime);

        public string AddRecurringJob(string jobId, Expression<Action> expression, string cron)
        {
            RecurringJob.AddOrUpdate(jobId, expression, cron, JobOptions);
            LoadedJobIds.Add(jobId);
            return jobId;
        }

        public string AddRecurringJob<T>(string jobId, Expression<Action<T>> expression, string cron) where T : class
        {
            RecurringJob.AddOrUpdate<T>(jobId, expression, cron, JobOptions);
            LoadedJobIds.Add(jobId);
            return jobId;
        }

        #endregion

        #region 异步

        public void AddOnceJob(Expression<Func<Task>> expression) => BackgroundJob.Enqueue(expression);

        public void AddOnceJob(Expression<Func<Task>> expression, DateTimeOffset time) => BackgroundJob.Schedule(expression, time);

        public string AddRecurringJob(string jobId, Expression<Func<Task>> expression, string cron)
        {
            RecurringJob.AddOrUpdate(jobId, expression, cron, JobOptions);
            LoadedJobIds.Add(jobId);
            return jobId;
        }

        public string AddRecurringJob<T>(string jobId, Func<T, Task> func, string cron) where T : class
        {
            RecurringJob.AddOrUpdate<T>(jobId, p => func.Invoke(p), cron, JobOptions);
            LoadedJobIds.Add(jobId);
            return jobId;
        }

        public void DelayJob(Expression<Func<Task>> expression, TimeSpan delayTime) => BackgroundJob.Schedule(expression, delayTime);

        #endregion

        public void RemoveJob(string jobId)
        {
            RecurringJob.RemoveIfExists(jobId);
            LoadedJobIds.Remove(jobId);
        }

    }
}